package com.bsj.media.network;

import com.bsj.consumerQ.until.ExceptionUntil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Locale;
import java.util.concurrent.TimeUnit;


@Slf4j
@Component
public class HttpNettyUntil {

    private final int CONST_THREAD_BOSS = 4;
    private final int CONST_THREAD_WORKER = 8;
    private ServerBootstrap bootstrap = null;
    private EventLoopGroup boss_group = null;
    private EventLoopGroup worker_group = null;

    public boolean start(int port) {
        this.bootstrap = new ServerBootstrap();
        String os = System.getProperty("os.name");
        if (os.toLowerCase(Locale.ENGLISH).contains("linux")) {
            this.boss_group = new EpollEventLoopGroup(CONST_THREAD_BOSS);
            this.worker_group = new EpollEventLoopGroup(CONST_THREAD_WORKER);
            bootstrap.channel(EpollServerSocketChannel.class);
        } else {
            this.boss_group = new NioEventLoopGroup(CONST_THREAD_BOSS);
            this.worker_group = new NioEventLoopGroup(CONST_THREAD_WORKER);
            bootstrap.channel(NioServerSocketChannel.class);
        }
        this.bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
        this.bootstrap.group(boss_group, worker_group).childHandler(new ChannelInitializer<SocketChannel>(){
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline p = ch.pipeline();
                // 自动空闲检测，如果10分钟没有接收和发出数据则断开连接
                p.addLast(new IdleStateHandler(0, 0, 10,
                        TimeUnit.MINUTES));
                // 添加http加解码器
                p.addLast("http-codec", new HttpServerCodec());
                p.addLast("http-aggregator", new HttpObjectAggregator(65536));
                p.addLast("http-chunked", new ChunkedWriteHandler());
                p.addLast("handler", new HttpRequestHandler());
            }
        });
        this.bootstrap.childOption(ChannelOption.WRITE_BUFFER_WATER_MARK,
                new WriteBufferWaterMark(1024 * 100, 1024 * 500));
        this.bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
        this.bootstrap.childOption(ChannelOption.TCP_NODELAY, false);
        this.bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
        this.bootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
        try {
            this.bootstrap.bind(port).sync();
        } catch (InterruptedException e) {
            log.error("NettyHttp初始化失败，端口：" + port + " 错误信息：" + ExceptionUntil.getErrorStr(e));
            return false;
        }
        return true;
    }

    public void stop() {
        this.boss_group.shutdownGracefully();
        this.worker_group.shutdownGracefully();
        this.boss_group = null;
        this.worker_group = null;
        this.bootstrap = null;
    }
}
